package com.thprojects.myphotomemories.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import exception.PhotoSourceNotFoundException;
import exception.SDNotReadyException;

public class FSController {
	
	Context mContext;
	
	//design pattern singleton	
	private static FSController singleton = null;

	
    private FSController(Context context) {
        mContext = context;
    }
    
    public static FSController getFSController(Context context){
    	if (singleton == null) singleton = new FSController(context);    	
    	return singleton;
    }
    
    public String saveImageCopy(String fileName) throws SDNotReadyException{
    	if (!isExternalStorageWritable()) return null;
    	return createExternalStoragePrivatePicture(fileName);
    }
    
    
    private boolean isExternalStorageWritable(){
    	String state = Environment.getExternalStorageState();

    	if (Environment.MEDIA_MOUNTED.equals(state)) {
    	    // We can read and write the media
    	    return true;
    	} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    	    // We can only read the media
    	    return false;
    	} else {
    	    // Something else is wrong. It may be one of many other states, but all we need
    	    //  to know is we can neither read nor write
    	    return false;
    	}
    }
    
    private boolean isExternalStorageReadable(){
    	String state = Environment.getExternalStorageState();

    	if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    	    // We can read and write the media
    	    return true;
    	} else {
    	    // Something else is wrong. It may be one of many other states, but all we need
    	    //  to know is we can neither read nor write
    	    return false;
    	}
    }
    
    public String getTimeStamp(){
    	SimpleDateFormat s = new SimpleDateFormat("yyyyMMddhhmmss");
    	return s.format(new Date());
    }
    
    private String createExternalStoragePrivatePicture(String fileName) throws SDNotReadyException{
    	if (!isExternalStorageWritable()) throw new SDNotReadyException("Can't write your SD card. Please make sure that it is properly inserted.");
        // Create a path where we will place our picture in our own private
        // pictures directory.  Note that we don't really need to place a
        // picture in DIRECTORY_PICTURES, since the media scanner will see
        // all media in these directories; this may be useful with other
        // media types such as DIRECTORY_MUSIC however to help it classify
        // your media for display to the user.
        File path = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        Log.d("MPM","path: "+path);
        File file = new File(path, getTimeStamp()+".jpg");

        try {
                    	
        	InputStream is = new FileInputStream(fileName);
            OutputStream os = new FileOutputStream(file);
            byte[] data = new byte[is.available()];
            is.read(data);
            os.write(data);
            is.close();
            os.close();

            // Tell the media scanner about the new file so that it is
            // immediately available to the user.
            MediaScannerConnection.scanFile(mContext,
                    new String[] { file.toString() }, null,
                    new MediaScannerConnection.OnScanCompletedListener() {
                public void onScanCompleted(String path, Uri uri) {
                    Log.i("MPM", "Scanned " + path + ":");
                    Log.i("MPM", "-> uri=" + uri);
                }
            });
        } catch (IOException e) {
            // Unable to create file, likely because external storage is
            // not currently mounted.
            Log.w("MPM", "Error writing " + file, e);
        }
        
        return file.getPath();
    }
    
    public String savePicture(Bitmap img, String path) throws SDNotReadyException{
    	if (!isExternalStorageReadable()) throw new SDNotReadyException("Can't read your SD card. Please make sure that it is properly inserted.");

        File file = new File(path);

        try {
            OutputStream os = new FileOutputStream(file);
            img.compress(Bitmap.CompressFormat.JPEG, 100, os);

        } catch (IOException e) {
            // Unable to create file, likely because external storage is
            // not currently mounted.
            Log.w("MPM", "Error writing " + file, e);
        }
        
        return file.getPath();
    }

    
    public void deleteExternalStoragePrivatePicture(String filePath) throws SDNotReadyException{
        // Create a path where we will place our picture in the user's
        // public pictures directory and delete the file.  If external
        // storage is not currently mounted this will fail.
    	if (!isExternalStorageReadable()) throw new SDNotReadyException("Can't read your SD card. Please make sure that it is properly inserted.");
    	
        //File path = c.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        if (filePath != null) {
            File file = new File(filePath);
            file.delete();
        }
    }

    public boolean hasExternalStoragePrivatePicture(String fileName) {
        // Create a path where we will place our picture in the user's
        // public pictures directory and check if the file exists.  If
        // external storage is not currently mounted this will think the
        // picture doesn't exist.
        File path = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        if (path != null) {
            File file = new File(path, fileName);
            return file.exists();
        }
        return false;
    }
    
    private boolean doesFileExist(String filePath){
        File file = new File(filePath);
        return file.exists();
    }
    
    //bitmap utility methods
    
    public Bitmap loadMinOptimizedBitmap(String filePath, int minWidth, int minHeight) throws PhotoSourceNotFoundException, SDNotReadyException{
		
    	if (!isExternalStorageReadable()) throw new SDNotReadyException("Can't read your SD card. Please make sure that it is properly inserted.");
		if (!doesFileExist(filePath)) throw new PhotoSourceNotFoundException("Image file not found");
		
		int w=0, h=0;
		
		int minDim = minWidth <= minHeight? minWidth : minHeight;
		
		if (minWidth <= minHeight){
			minHeight = minDim * minHeight / minWidth;
			minWidth = minDim;
		}
		else{
			minWidth = minDim * minWidth / minHeight;
			minHeight = minDim;
		}
		
		return decodeSampledBitmap(filePath, w, h);
	}
	
	private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
	    // Raw height and width of image
	    final int height = options.outHeight;
	    final int width = options.outWidth;
	    int inSampleSize = 1;
	
	    if (height > reqHeight || width > reqWidth) {
	        if (width > height) {
	            inSampleSize = Math.round((float)height / (float)reqHeight);
	        } else {
	            inSampleSize = Math.round((float)width / (float)reqWidth);
	        }
	    }
	    return inSampleSize;
	}
	
	public Bitmap decodeSampledBitmap(String filePath, int reqWidth, int reqHeight)  throws PhotoSourceNotFoundException, SDNotReadyException{
		
		if (!isExternalStorageReadable()) throw new SDNotReadyException("Can't read your SD card. Please make sure that it is properly inserted.");
		if (!doesFileExist(filePath)) throw new PhotoSourceNotFoundException("Image file not found");

	    // First decode with inJustDecodeBounds=true to check dimensions
	    final BitmapFactory.Options options = new BitmapFactory.Options();
	    options.inJustDecodeBounds = true;
	    BitmapFactory.decodeFile(filePath, options);

	    // Calculate inSampleSize
	    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

	    // Decode bitmap with inSampleSize set
	    options.inJustDecodeBounds = false;
	    return BitmapFactory.decodeFile(filePath, options);
	}
	
	
	
}
